#ifndef INDEXED_VERTEX_BUFFER
#define INDEXED_VERTEX_BUFFER

#include "EngineApi.h"
#include "Struct.h"

#include <d3d9.h>
#include <windows.h>

template <class PixelFormatClass, unsigned int FVF>
class __declspec(dllexport) IndexedVertexBuffer
{
public:
   IndexedVertexBuffer(unsigned short vbSize = 1000000, unsigned short ibSize = 1000000): 
      m_VertexBufferSize(vbSize),
      m_IndexBufferSize(ibSize),
      m_pDxDevice(NULL),
      m_pVertexBuffer(NULL),
      m_pIndexBuffer(NULL){}

   bool create(LPDIRECT3DDEVICE9 pDxDevice)
   {
      m_pDxDevice = pDxDevice;
      
      HRESULT hr = m_pDxDevice->CreateVertexBuffer(m_VertexBufferSize * sizeof(PixelFormatClass),
         D3DUSAGE_WRITEONLY,
         FVF,
         D3DPOOL_MANAGED,
         &m_pVertexBuffer,
         NULL);

      if (hr != D3D_OK)
      {
         std::cout << "failed to create Vertex Buffer" << std::endl;
         return false;
      }
      
      hr = m_pDxDevice->CreateIndexBuffer(m_IndexBufferSize * sizeof(unsigned int),
         D3DUSAGE_WRITEONLY,
         D3DFMT_INDEX32,
         D3DPOOL_MANAGED,
         &m_pIndexBuffer,
         NULL);

      if (hr != D3D_OK)
      {
         std::cout << "failed to create Index Buffer" << std::endl;
         return false;
      }

      return true;
   }
   
   void bind()
   {
      m_pDxDevice->SetFVF(FVF);
      m_pDxDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(PixelFormatClass));

      m_pDxDevice->SetIndices(m_pIndexBuffer);
   }

   bool draw(unsigned short vertexCount, PixelFormatClass* pVertexColection,
             unsigned short indexCount,  unsigned int* pIndexColection,
             unsigned short primitiveCount, PRIM_TYPE primitiveType)
   {
      //Indices
      void* pIndices; 

      HRESULT hr = m_pIndexBuffer->Lock( 
         0,                                            // Fill from start of the buffer
         indexCount * sizeof(unsigned int),   // Size of the data to load
         &pIndices,                                    // Returned index data
         0 );                                          // Send default flags to the lock

      if (FAILED(hr))
      {
         std::cout << "failed to Lock indices" << std::endl;
         return false;
      }

      memcpy(pIndices,pIndexColection,indexCount * sizeof(unsigned int));
      m_pIndexBuffer->Unlock();

      //Vertices
      void* pVertices;

      hr = m_pVertexBuffer->Lock(0,m_VertexBufferSize * sizeof(PixelFormatClass),&pVertices,0);

      if (FAILED(hr))
      {
         std::cout << "failed to Lock vertices" << std::endl;
         return false;
      }

      memcpy(pVertices,pVertexColection,sizeof(PixelFormatClass) * vertexCount); 
      m_pVertexBuffer->Unlock();  

      m_pDxDevice->DrawIndexedPrimitive(static_cast<D3DPRIMITIVETYPE>(primitiveType),0,0,vertexCount,0,primitiveCount);
   
      return true;
   }

private:
   LPDIRECT3DDEVICE9 m_pDxDevice;
   
   LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer;
   unsigned short m_VertexBufferSize;
   
   LPDIRECT3DINDEXBUFFER9 m_pIndexBuffer;
   unsigned short m_IndexBufferSize;
};

#endif//INDEXED_VERTEX_BUFFER